package node

import (
	"encoding/hex"
	"github.com/gogf/gf/container/gqueue"
	"github.com/zeromicro/go-zero/core/syncx"
	"io"
	"log"
	"sieve_engine/execute/whatsapp/lib/protocol/iface"
	"sieve_engine/execute/whatsapp/lib/wslog"
	"sync"
)

type processor struct {
	close         *syncx.AtomicBool //TODO linhx modify
	closedQueue   *syncx.AtomicBool //TODO linhx add
	closeLock     *sync.Mutex       //TODO linhx add
	segmentOutput iface.SegmentOutputProcessor
	sendQueue     *gqueue.Queue
}

func Processor(s iface.SegmentOutputProcessor) *processor {
	p := &processor{
		close:         syncx.ForAtomicBool(false), //TODO linhx add
		closedQueue:   syncx.ForAtomicBool(false), //TODO linhx add
		closeLock:     &sync.Mutex{},              //TODO linhx add
		segmentOutput: s,
		sendQueue:     gqueue.New(), //不受限
	}

	// run
	go func() {
		p.runSendQueue()
	}()
	return p
}

// Close
func (p *processor) Close() bool {
	//TODO linhx add
	p.closeLock.Lock()
	defer p.closeLock.Unlock()

	if p.closedQueue.True() {
		return false
	}
	p.closedQueue.Set(true)
	//TODO linhx end
	p.close.Set(false)
	p.sendQueue.Close()
	return true
}

// SendBuilder
func (p *processor) SendBuilder(b iface.NodeBuilder) {
	//TODO linhx add
	p.closeLock.Lock()
	defer p.closeLock.Unlock()
	if !p.close.True() && p.closedQueue.True() {
		wslog.GetLogger().Debug("SendBuilder !p.close && closedQueue == true")
		return
	}
	//TODO linhx end

	// Confirm whether the queue is closed and build
	if !p.close.True() && b == nil {
		wslog.GetLogger().Debug("SendBuilder !p.close && b == nil")
		return
	}
	p.sendQueue.Push(b)
}

// SendData 这个应该放到 NetWork里
func (p *processor) SendData(d []byte) error {
	//TODO linhx modify
	err, _ := p.segmentOutput.WriteSegmentOutputData(d)
	return err
}

// runSendChan
func (p *processor) runSendQueue() {
	p.close.Set(true)
	p.closedQueue.Set(false)

	for {
		if v := p.sendQueue.Pop(); v == nil {
			p.Close()
			// 退出队列
			log.Println("Exit run send queue")
			break
		} else {
			if builder, ok := v.(iface.NodeBuilder); ok {
				nodeData, err := builder.Builder()
				wslog.GetLogger().Debug("send builder", hex.EncodeToString(nodeData), err)
				err = p.SendData(nodeData)
				if err != nil {
					if err == io.EOF {
						//TODO 连接断开了
						break
					}
					// TODO 其他错误
					if ipromise, ok := v.(iface.IPromise); ok {
						if promise := ipromise.GetPromise(); promise != nil {
							promise.Reject(err)
						}
					}
				}
			} else {
				log.Println("I got the wrong object", v)
			}
		}
	}
	// 关闭队列
	if p.close.True() {
		p.Close()
	}
}
